package au.org.htd.youslide;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;

import net.sourceforge.pinyin4j.PinyinHelper;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import au.org.htd.youslide.ppt.DisplayText;

import com.google.appengine.api.datastore.Blob;
import com.google.appengine.api.datastore.Text;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class SongProject extends DbObject implements Cloneable {
   public SongProject(PersistenceManager pm) {
      super(pm);
   }

   @SuppressWarnings("unused")
   private static final Logger log = Logger.getLogger(SongProject.class
         .getName());

   private static final String DEFAULT_FILE_NAME = "song";
   @Persistent
   private String englishName;

   @Persistent
   private String chineseName;

   @Persistent
   private String firstLetter;

   @Persistent
   private Text englishLyrics;

   @Persistent
   private Text chineseLyrics;

   @Persistent
   private List<Attachment> attachments;

   @Persistent
   private String audioUrl;

   @Persistent
   private Long backgroundId;

   @Persistent
   private String tags = "";

   public String getTags() {
      return tags;
   }

   public void setTags(String tags) {
      this.tags = "";
      if (null == tags) {
         return;
      }
      StringTokenizer tok = new StringTokenizer(tags);
      while (tok.hasMoreTokens()) {
         this.tags += ("," + tok.nextToken());
      }
   }

   public void addTag(String tag) {
      if (null == tags) {
         tags = "";
      }
      tags += (tags.length() > 0 ? "," : "") + tag;
   }

   public void removeTag(String tag) {
      tags = tags.replaceAll("," + tag, "").replaceAll(tag + ",", "")
            .replaceAll(tag, "");
   }

   public Long getBackgroundId() {
      return backgroundId;
   }

   public void setBackgroundId(Long backgroundId) {
      this.backgroundId = backgroundId;
   }

   public String getEnglishName() {
      return englishName;
   }

   public void setEnglishName(String englishName) {
      this.englishName = englishName;
      if (!Util.isEmpty(englishName)) {
         this.firstLetter = "" + englishName.charAt(0);
      }
      if (englishName.charAt(0) >= (char) '0'
            && englishName.charAt(0) <= (char) '9') {
         this.firstLetter = "0-9";
      }
   }

   public String getChineseName() {
      return chineseName;
   }

   public void setChineseName(String chineseName) {
      this.chineseName = chineseName;
      if (!Util.isEmpty(chineseName) && null == firstLetter) {
         this.firstLetter = ""
               + PinyinHelper.toHanyuPinyinStringArray(chineseName.charAt(0))[0]
                     .charAt(0);
      }
   }

   public String getEnglishLyrics() {
      return englishLyrics.getValue();
   }

   public void setEnglishLyrics(String englishLyrics) {
      this.englishLyrics = new Text(englishLyrics);
   }

   public String getChineseLyrics() {
      return chineseLyrics.getValue();
   }

   public void setChineseLyrics(String chineseLyrics) {
      this.chineseLyrics = new Text(chineseLyrics);
   }

   public String getAudioUrl() {
      return audioUrl;
   }

   public void setAudioUrl(String audioUrl) {
      this.audioUrl = audioUrl;
   }

   public DisplayText getName() {
      return new DisplayText(englishName, chineseName);
   }

   public DisplayText getLyrics() {
      return new DisplayText(getEnglishLyrics(), getChineseLyrics());
   }

   public void setName(DisplayText name) {
      setEnglishName(name.getEnglishText());
      setChineseName(name.getChineseText());
   }

   public void setLyrics(DisplayText lyrics) {
      setEnglishLyrics(lyrics.getEnglishText());
      setChineseLyrics(lyrics.getChineseText());
   }

   public Long getAge() {
      return (new Date().getTime() - getLastUpdate().getTime())
            / (1000 * 60 * 60 * 24);
   }

   public String getFileName() {
      if (null != englishName && null != chineseName) {
         return getEnglishFileName() + " | " + getChineseFileName();
      } else if (null != englishName) {
         return getEnglishFileName();
      } else if (null != chineseName) {
         return getChineseFileName();
      } else {
         return DEFAULT_FILE_NAME;
      }
   }

   public String getEnglishFileName() {
      return englishName;
   }

   public String getChineseFileName() {
      try {
         return URLEncoder.encode(chineseName, "UTF-8");
      } catch (UnsupportedEncodingException e) {
         return DEFAULT_FILE_NAME;
      }
   }

   public List<Attachment> getAttachments() {
      return attachments;
   }

   public JSONObject toJSON() {
      JSONObject info = new JSONObject();
      try {
         info.put("id", getId());
         if (null != getBackgroundId()) {
            info.put("bgId", getBackgroundId().intValue());
         }
         info.put("englishName", getEnglishName());
         info.put("creator", getCreatorName());
         String when;
         int days = getAge().intValue();
         switch (days) {
         case 0:
            when = "today";
            break;
         case 1:
            when = "yesterday";
            break;
         default:
            when = days + " days ago";
         }
         info.put("when", when);
         info.put("chineseName", getChineseName());
         info.put("audioUrl", getAudioUrl());
      } catch (JSONException e) {
         e.printStackTrace();
      }

      return info;
   }

   @SuppressWarnings("unchecked")
   public static JSONArray searchByLetter(String pLetter) throws IOException {
      PersistenceManager pm = PMF.getPM();
      if ("0-9".equals(pLetter)) {
         return searchByNumbers();
      }

      String query = "select from " + SongProject.class.getName()
            + " where (firstLetter >= \"" + pLetter + "\" &&"
            + " firstLetter <  \"" + (char) (pLetter.charAt(0) + 1) + "\")";

      JSONArray result = new JSONArray();
      for (SongProject song : (List<SongProject>) pm.newQuery(query).execute()) {
         result.put(song.toJSON());
      }
      pm.close();

      if (pLetter.toUpperCase().equals(pLetter)) {
         JSONArray lower = searchByLetter(pLetter.toLowerCase());
         for (int i = 0; i < lower.length(); i++) {
            try {
               result.put(lower.get(i));
            } catch (JSONException ignore) {
            }
         }
      }
      return result;
   }

   @SuppressWarnings("unchecked")
   public static JSONArray searchByNumbers() throws IOException {
      PersistenceManager pm = PMF.getPM();
      String query = "select from " + SongProject.class.getName()
            + " where (firstLetter >= \"0\" && firstLetter < \"9\")";

      JSONArray result = new JSONArray();
      for (SongProject song : (List<SongProject>) pm.newQuery(query).execute()) {
         result.put(song.toJSON());
      }
      pm.close();
      return result;
   }

   public JSONArray getTagsArray() throws IOException, JSONException {
      JSONArray result = new JSONArray();
      StringTokenizer tok = new StringTokenizer(tags, ",");
      while (tok.hasMoreTokens()) {
         Tag tag = Tag.getTagByName(pm, tok.nextToken());
         JSONObject jtag = new JSONObject();
         jtag.put("name", tag.getName());
         jtag.put("count", tag.songCount());
         result.put(jtag);
      }
      return result;
   }

   public int attach(String url) throws AppException {
      String name = url.substring(url.lastIndexOf('/') + 1);
      return attach(Util.getBytesFromURL(url), name);
   }

   public int attach(byte[] data, String name) {
      attachments.add(new Attachment(name, new Blob(data)));
      return attachments.size() - 1;
   }

   public String getFirstLetter() {
      return firstLetter;
   }

   public boolean contains(String str) {
      str = str.toLowerCase();
      return ((getEnglishLyrics().toLowerCase().indexOf(str) >= 0)
            || (getChineseLyrics().toLowerCase().indexOf(str) >= 0)
            || (getEnglishName().toLowerCase().indexOf(str) >= 0) || (getChineseName()
            .toLowerCase().indexOf(str) >= 0));
   }

   @SuppressWarnings("unchecked")
   public static JSONArray searchByContent(String content) {
      PersistenceManager pm = PMF.getPM();
      String query = "select from " + SongProject.class.getName();

      JSONArray result = new JSONArray();
      for (SongProject song : (List<SongProject>) pm.newQuery(query).execute()) {
         if (song.contains(content)) {
            result.put(song.toJSON());
         }
      }
      pm.close();
      return result;
   }

   @SuppressWarnings("unchecked")
   public static JSONArray searchByCreator(String creator) {
      PersistenceManager pm = PMF.getPM();
      String query = "select from " + SongProject.class.getName();

      JSONArray result = new JSONArray();
      for (SongProject song : (List<SongProject>) pm.newQuery(query).execute()) {
         if (song.getCreatorName().equals(creator)) {
            result.put(song.toJSON());
         }
      }
      pm.close();
      return result;
   }

   @Override
   public SongProject get(Long id) {
      SongProject song = pm.getObjectById(SongProject.class, id);
      song.setPm(pm);
      return song;
   }
}
